/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package classcreator;

import java.util.Vector;

/**
 *
 * @author Stefano
 */
public class StateMachineTester {
    StateMachine sm;
    
    public StateMachineTester(StateMachine sm){
        this.sm=sm;
    }
    
    public String getPathTestTitle(Path path, int pathNumber){
        String s="testPath"+pathNumber+"onStates_";
        for(GuardedTransition gt:path){
            if(gt.startState.id>=0)s=s+gt.startState.id+"_";
            else s=s+"minus"+(-gt.startState.id)+"_";
        }
        if(path.size()>0){
           if(path.lastElement().endState.id>=0) s=s+path.lastElement().endState.id;
           else s=s+"minus"+(-path.lastElement().endState.id);
        }
        return s;
    }
    
    public String getTestParametersAndCall(TestParameterGenerator tpm, MethodHeader mh){
        String s="";
        Vector<Parameter> params=new Vector<Parameter>();
        for(Parameter p:mh.parameters){
            Parameter parameter=new Parameter(p.type,tpm.getName(p.type));
            params.add(parameter);
            s=s+Naming.tab+parameter.toString()+";\n";
        }
        s=s+Naming.tab+Naming.stateMachineParameterName+"."+mh.name+"(";
        for(Parameter p:params){
            s=s+p.name+",";
        }
        if(params.size()>0){
            s=s.substring(0, s.length()-1);
        }
        s=s+");\n";
        return s;
    }
    
    public String getTransitionTest(TestParameterGenerator tpm, GuardedTransition gt){
        String s="";
        String message="The conditions of guard [ "+gt.guard+" ] at transition "+gt.transition.header.name+" from state "+gt.startState.name+" to state "+gt.endState.name+" is not verified.";
        s=s+Naming.tab+ "assertTrue(\""+message+"\", true /* "+gt.guard+" */);\n";
        s=s+ getTestParametersAndCall(tpm,gt.transition.header);
        message="Transition "+gt.transition.header.name+" from state "+gt.startState.name+" to state "+gt.endState.name+" with guard [ "+gt.guard+" ] verified did not reach the correct end state.";
        s=s+Naming.tab+ "assertTrue(\""+message+"\", "+Naming.stateMachineParameterName+"."+Naming.stateMachineGetState+"("+gt.endState.id+"));\n";
        return s;
    }
    
    public String getPathTest(Path path, int pathNum){
        TestParameterGenerator tpm=new TestParameterGenerator();
        String s="";
        
        //s=s+"@Test\n";
        s=s+"@TransitionDiagram(\""+path.toString()+"\")\n";
        s=s+"public void "+getPathTestTitle(path, pathNum)+"(){\n";
        if(path.size()>0){
            s=s+Naming.tab+sm.name+" "+Naming.stateMachineParameterName+";\n";
            String message="StateMachine is not in the correct path starting state.";
            s=s+Naming.tab+ "assertTrue(\""+message+"\", "+Naming.stateMachineParameterName+"."+Naming.stateMachineGetState+"("+path.firstElement().startState.id+"));\n\n";
            for(GuardedTransition gt:path){
                s=s+getTransitionTest(tpm,gt)+"\n";
            }
        }
        s=s+"}\n";
        return s;
    }
    
    public String getAuxiliaryTest(Method m){
        TestParameterGenerator tpm=new TestParameterGenerator();
        MethodHeader mh=m.header;
        String s="";
        s=s+"public void testAuxiliary_"+m.header.name+"(){\n";
        if(m.header.returnType.equals(Naming.voidType)){
            String message="Auxiliary method is void, nothing to assert.";
            s=s+Naming.tab+ "assertTrue(\""+message+"\", true);\n\n";
        }
        else{
            Vector<Parameter> params=new Vector<Parameter>();
            s=s+Naming.tab+sm.name+" "+Naming.stateMachineParameterName+";\n";
            for(Parameter p:mh.parameters){
                Parameter parameter=new Parameter(p.type,tpm.getName(p.type));
                params.add(parameter);
                s=s+Naming.tab+parameter.toString()+";\n";
            }
            s=s+Naming.tab+m.header.returnType.name+" "+tpm.getName(m.header.returnType)+" = "+Naming.stateMachineParameterName+"."+mh.name+"(";
            for(Parameter p:params){
                s=s+p.name+",";
            }
            if(params.size()>0){
                s=s.substring(0, s.length()-1);
            }
            s=s+");\n";

            String message="Result of auxiliary method "+m.header.name+" is not as expected.";
            s=s+Naming.tab+ "assertTrue(\""+message+"\", true /* test result */);\n\n";
        }
        
        s=s+"}\n";
        return s;
    }
    
    public String getClassName(){
        return "JUnit_"+sm.name;
    }
    
    public String toString(){
        Vector<Path> paths=getPaths(0);
        
        String s="";
        s=s+"package "+Naming.defaultPackageName+";\n";
        s=s+"import junit.framework.TestCase;\n";
        //s=s+"import junit.framework.TestCase;\n";
        //s=s+"import org.junit.Test;\n";
        s=s+"\n";
        s=s+"@StateTags(stateTags={\n";
        for(State st:sm.states){
            s=s+Naming.tab+"@StateTag(tag="+st.id+", name=\""+st.name+"\"),\n";
        }
        if(sm.states.size()>0){
            s=s.substring(0, s.length()-2);
            s=s+"\n";
        }
        s=s+"})\n";
        
        s=s+"public class "+getClassName()+" extends TestCase{\n";
        for(int i=0; i<paths.size(); i++){
            s=s+getPathTest(paths.get(i),i)+"\n";
        }
        
        for(Method m:sm.methods){
            s=s+getAuxiliaryTest(m)+"\n";
        }
        
        s=s+"}\n";
        return s;
    }
    
    public Vector<Path> getPaths(int startStateID){
        Vector<Path> paths = new Vector<Path>();
        Vector<Integer> visitedStates = new Vector<Integer>();
        State state = sm.getStateFromID(startStateID);
        //System.out.println(startStateID+": "+state.name);
        Path path=new Path();
        if(state==null) return paths;
        
        addPaths(paths, visitedStates, state, path);
        
        return paths;
    }
    
    private void addPaths(Vector<Path> paths, Vector<Integer> visitedStates, State state, Path path){
        Vector<GuardedTransition> transitionsFromState=transitionsFromState(state.id);
        //System.out.println("Transitions from state "+state.name+": "+transitionsFromState);
        if(transitionsFromState.size()<=0){
            paths.add(path);
            return;
        }
        for(Integer i:visitedStates){
            if(i.intValue()==state.id){
                paths.add(path);
                return;
            }
        }
        visitedStates.add(state.id);
        
        for(int i=1; i<transitionsFromState.size(); i++){
            GuardedTransition gt=transitionsFromState.get(i);
            Path newpath=new Path(path);
            newpath.add(gt);
            addPaths(paths, (Vector<Integer>) visitedStates.clone(), gt.endState,newpath);
        }
        
        GuardedTransition gt=transitionsFromState.get(0);
        path.add(gt);
        addPaths(paths, (Vector<Integer>) visitedStates, gt.endState,path);
    }
    
    public Vector<GuardedTransition> transitionsFromState(int stateID){
        Vector<GuardedTransition> trans=new Vector<GuardedTransition>();
        State state=sm.getStateFromID(stateID);
        if(state==null) return trans;
        for(Transition t:sm.transitions){
            for(TransitionInfo ti:t.transinfo){
                if(ti.start==stateID){
                    State endState=sm.getStateFromID(ti.end);
                    if(endState==null) continue;
                    trans.add(new GuardedTransition(t, state, endState, (ti.guard.isEmpty()?"true":ti.guard)));
                }
            }
        }
        return trans;
    }
    
    public Vector<GuardedTransition> transitionsToState(int stateID){
        Vector<GuardedTransition> trans=new Vector<GuardedTransition>();
        State state=sm.getStateFromID(stateID);
        if(state==null) return trans;
        for(Transition t:sm.transitions){
            for(TransitionInfo ti:t.transinfo){
                if(ti.end==stateID){
                    State startState=sm.getStateFromID(ti.start);
                    if(startState==null) continue;
                    trans.add(new GuardedTransition(t, startState, state, (ti.guard.isEmpty()?"true":ti.guard)));
                }
            }
        }
        return trans;
    }
    
    public Vector<GuardedTransition> transitionsFromStateToState(int startStateID, int endStateID){
        Vector<GuardedTransition> trans=new Vector<GuardedTransition>();
        State state=sm.getStateFromID(startStateID);
        State endState=sm.getStateFromID(endStateID);
        if(state==null) return trans;
        if(endState==null) return trans;
        for(Transition t:sm.transitions){
            for(TransitionInfo ti:t.transinfo){
                if(ti.start==startStateID && ti.end==endStateID){
                    trans.add(new GuardedTransition(t, state, endState, (ti.guard.isEmpty()?"true":ti.guard)));
                }
            }
        }
        return trans;
    }
}
